package com.haochang.chunkvod.view.vod.expandTextView;

import java.util.ArrayList;
import java.util.List;

import com.haochang.chunkvod.R;
import com.haochang.chunkvod.app.utils.CollectionUtils;

import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;

/**
 * @author qintao
 *         created at 2016/10/24 11:15
 *         带缩放展开动画效果的简单TextView
 */
public class ExpandTextView extends View implements View.OnClickListener
{
	//行文本记录集
	private List<LineText> lineTexts = new ArrayList<LineText>();
	//最大显示文本行数
	private int maxLines;
	//目标文本行
	private int targetLine;
	//收缩收起时候的提示图标
	private Drawable expandDrawable;
	//展开时候的提示图标
	private Drawable shrinkDrawable;
	//提示图标的宽度
	private int drawableWidth;
	//提示图标的高度
	private int drawableHeight;
	//最大显示文本行对应的本视图高度
	private int maxLinesHeight;
	//展开时候的视图高度
	private int expandHeight;
	//当前视图的高度
	private int viewHeight;
	//收缩行结尾提示语文本宽度
	private float ellipsizeWidth;
	//收缩行结尾提示语文本绘制水平起点
	private float ellipsizeStartX;
	//提示操作文本的宽度(默认：展开)
	private float textTipWidth;
	//文本字体高度
	private float mTextHeight;
	//文本字体高度Y偏移量
	private float mTextHeightY;
	//提示操作文本1
	private String textExpand;
	//提示操作文本2
	private String textShrink;
	//提示操作文本颜色
	private int textTipColor;
	//文本字体大小
	private int textSize;
	//文本颜色
	private int textColor;
	//当前文本
	private String text;
	private final String ELLIPSIZE_TEXT = "...";
	//收缩行文本
	private String shrinkLineText;
	//动画显示时间
	private int animDuration;
	//是否能够显示 ellipsizeText 【需要收缩行当前文本的宽度】
	private boolean showEllipsizeText = false;
	private boolean showTipDrawable = false;
	private boolean needMeasure = true;
	private StaticLayout layout;
	private TextPaint textPaint;

	public ExpandTextView(Context context)
	{
		this(context, null);
	}

	public ExpandTextView(Context context, AttributeSet attrs)
	{
		this(context, attrs, 0);
	}

	public ExpandTextView(Context context, AttributeSet attrs, int defStyleAttr)
	{
		super(context, attrs, defStyleAttr);
		TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ExpandTextView);
		maxLines = ta.getInt(R.styleable.ExpandTextView_maxLines, -1);
		animDuration = ta.getInt(R.styleable.ExpandTextView_animDuration, 300);
		textSize = ta.getDimensionPixelSize(R.styleable.ExpandTextView_textSize, 14);
		textColor = ta.getColor(R.styleable.ExpandTextView_textColor, 0xFFFFFFFF);
		expandDrawable = ta.getDrawable(R.styleable.ExpandTextView_expandDrawable);
		shrinkDrawable = ta.getDrawable(R.styleable.ExpandTextView_shrinkDrawable);
		drawableWidth = expandDrawable.getIntrinsicWidth();
		drawableHeight = expandDrawable.getIntrinsicHeight();
		textExpand = ta.getString(R.styleable.ExpandTextView_textExpand);
		textShrink = ta.getString(R.styleable.ExpandTextView_textShrink);
		textTipColor = ta.getColor(R.styleable.ExpandTextView_textTipColor, 0xFFFFFFFF);
		ta.recycle();
		textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
		textPaint.density = context.getResources().getDisplayMetrics().density;
		textPaint.setColor(textColor);
		textPaint.setStyle(Paint.Style.FILL_AND_STROKE);
		textPaint.setTextSize(textSize);
		Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
		mTextHeight = fontMetrics.bottom - fontMetrics.top;
		mTextHeightY = 0 - fontMetrics.top;
		//		Logger.e(drawableWidth + ":" + drawableHeight + ":" + mTextHeight + ":" + mTextHeightY);
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
	{
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		int width = MeasureSpec.getSize(widthMeasureSpec);
		if (needMeasure && (!TextUtils.isEmpty(text)))
		{
			needMeasure = false;
			measureHeightState(text, width);
		} else
		{
			heightMeasureSpec = getMyViewHeight(heightMeasureSpec, viewHeight);
			setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
		}
	}

	/**
	 * 获取view的具体高度
	 * @param heightMeasureSpec
	 * @param desired
	 * @return
	 */
	private int getMyViewHeight(int heightMeasureSpec, int desired)
	{
		int result = 0;
		int speSize = MeasureSpec.getSize(heightMeasureSpec);
		int speMode = MeasureSpec.getMode(heightMeasureSpec);
		switch (speMode)
		{
		case MeasureSpec.UNSPECIFIED:
			result = desired;
			break;
		case MeasureSpec.AT_MOST:
			result = Math.min(speSize, desired);
			break;
		case MeasureSpec.EXACTLY:
			result = speSize;
			break;
		default:
			break;
		}
		return result;
	}

	public void setText(String text)
	{
		if (!TextUtils.isEmpty(text))
		{
			this.text = text;
			needMeasure = true;
			requestLayout();
		}
	}

	private synchronized void measureHeightState(String text, int width)
	{
		layout = new StaticLayout(text, textPaint, width - getPaddingLeft() - getPaddingRight(), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0f, true);
		final int lineCount = layout.getLineCount();
		maxLines = (maxLines == -1 || maxLines > lineCount) ? lineCount : maxLines;
		int text_Height = 0;
		List<LineText> tempLines = new ArrayList<LineText>();
		maxLinesHeight = 0;
		expandHeight = 0;
		for (int index = 0; index < lineCount; index++)
		{
			int start = layout.getLineStart(index);
			int end = layout.getLineEnd(index);
			LineText lineText = new LineText();
			lineText.setStartIndex(start);
			lineText.setEndIndex(end - 1);
			lineText.setText(text.substring(start, end));
			lineText.setTopOffset(layout.getLineTop(index));
			lineText.setBottomOffset(layout.getLineBottom(index));
			lineText.setBaseLine(layout.getLineBaseline(index) + getPaddingTop());
			lineText.setWidth(layout.getLineWidth(index));
			lineText.setHeight(lineText.getBottomOffset() - lineText.getTopOffset());
			tempLines.add(lineText);
			if (index < maxLines)
			{
				maxLinesHeight += lineText.getHeight();
			}
			text_Height += lineText.getHeight();
		}
		maxLinesHeight += getPaddingTop() + getPaddingBottom();
		expandHeight += getPaddingTop() + getPaddingBottom();
		ellipsizeWidth = textPaint.measureText(ELLIPSIZE_TEXT);
		textTipWidth = textPaint.measureText(textShrink);
		if (maxLines < lineCount)
		{
			showTipDrawable = expandDrawable != null && shrinkDrawable != null;
			float textWidth = tempLines.get(maxLines - 1).getWidth();
			float contentWidth = width - getPaddingLeft() - getPaddingRight();
			float toMarginRight = ellipsizeWidth + (showTipDrawable ? drawableWidth + textTipWidth : 0) + 14;
			String ellipsizeLineText = tempLines.get(maxLines - 1).getText();
			if (contentWidth - textWidth < toMarginRight)
			{
				showEllipsizeText = true;
				String subString = null;
				for (int index = ellipsizeLineText.length() - 1; index > 0; index--)
				{
					subString = ellipsizeLineText.substring(0, index);
					float subStrWidth = textPaint.measureText(subString);
					if (contentWidth - subStrWidth >= toMarginRight)
					{
						ellipsizeStartX = subStrWidth + getPaddingLeft();
						shrinkLineText = subString;
						break;
					}
				}
			} else
			{
				shrinkLineText = ellipsizeLineText;
				showEllipsizeText = false;
			}
		} else
		{
			showTipDrawable = false;
			showEllipsizeText = false;
		}

		expandHeight += text_Height + ((expandDrawable != null && showTipDrawable) ? drawableHeight : 0);
		viewHeight = maxLines == lineCount ? expandHeight : maxLinesHeight;
		targetLine = maxLines;
		lineTexts = tempLines;
		if (viewHeight < expandHeight)
		{
			setClickable(true);
			setOnClickListener(this);
		} else
		{
			setClickable(false);
		}
	}

	@Override
	protected void onDraw(Canvas canvas)
	{
		super.onDraw(canvas);
		if (this.isInEditMode())
			return;
		if (CollectionUtils.isEmpty(lineTexts))
			return;
		for (int index = 0; index < targetLine; index++)
		{
			LineText lineText = lineTexts.get(index);
			if (index < targetLine - 1)
			{
				textPaint.setColor(textColor);
				canvas.drawText(lineText.getText(), getPaddingLeft(), lineText.getBaseLine(), textPaint);
			} else
			{
				int left = getWidth() - drawableWidth - getPaddingRight();
				int top = getHeight() - getPaddingBottom();
				if (targetLine == maxLines && maxLines < lineTexts.size())
				{
					textPaint.setColor(textColor);
					//收缩转态
					if (showEllipsizeText)
						canvas.drawText(ELLIPSIZE_TEXT, ellipsizeStartX, lineText.getBaseLine(), textPaint);
					canvas.drawText(shrinkLineText, getPaddingLeft(), lineText.getBaseLine(), textPaint);
					if (showTipDrawable)
					{
						textPaint.setColor(textTipColor);
						canvas.drawText(textExpand, left - textTipWidth - 6, top - mTextHeight + mTextHeightY, textPaint);
						canvas.drawBitmap(drawableToBitmap(shrinkDrawable), left, top - drawableHeight - (mTextHeight - drawableHeight) / 2, null);
					}
				} else if (targetLine == lineTexts.size())
				{
					//展开状态
					canvas.drawText(lineText.getText(), getPaddingLeft(), lineText.getBaseLine(), textPaint);
					if (showTipDrawable)
					{
						textPaint.setColor(textTipColor);
						canvas.drawText(textShrink, left - textTipWidth - 6, top - mTextHeight + mTextHeightY, textPaint);
						canvas.drawBitmap(drawableToBitmap(expandDrawable), left, top - drawableHeight - (mTextHeight - drawableHeight) / 2, null);
					}
				}
			}
		}
	}

	/**
	 * 动态设置控件高度
	 * @param viewHeight
	 */
	public void setViewHeight(int viewHeight)
	{
		this.viewHeight = viewHeight;
		requestLayout();
	}

	@Override
	public void onClick(View view)
	{
		if (maxLines == lineTexts.size())
			return;
		if (targetLine == maxLines)
		{
			targetLine = lineTexts.size();
			startDrawAnim(maxLinesHeight, expandHeight);
		} else if (targetLine == lineTexts.size())
		{
			targetLine = maxLines;
			startDrawAnim(expandHeight, maxLinesHeight);
		}
	}

	private void startDrawAnim(int startHeight, int endHeight)
	{
		ObjectAnimator animator = ObjectAnimator.ofInt(this, "viewHeight", startHeight, endHeight);
		animator.setDuration(animDuration);
		//        animator.setInterpolator(new AccelerateDecelerateInterpolator());
		animator.start();
	}

	/**
	 * Drawable转换成Bitmap
	 */
	public static Bitmap drawableToBitmap(Drawable drawable)
	{
		// 取 drawable 的长宽
		int width = drawable.getIntrinsicWidth();
		int height = drawable.getIntrinsicHeight();
		// 取 drawable 的颜色格式
		Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
		Bitmap bitmap = Bitmap.createBitmap(width, height, config);
		Canvas canvas = new Canvas(bitmap);
		drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
		drawable.draw(canvas);
		return bitmap;
	}

}
